import logging
import colorama
from colorama import Fore, Style
import threading
import json

colorama.init(autoreset=True)  # Reset color after each log output to avoid affecting subsequent text


class ColoredFormatter(logging.Formatter):
    """Custom log formatter to color different log levels"""

    LEVEL_COLORS = {
        logging.DEBUG: Fore.LIGHTBLACK_EX,  # Gray
        logging.INFO: Fore.BLACK,  # Default color (black/terminal default)
        logging.WARNING: Fore.YELLOW,  # Yellow
        logging.ERROR: Fore.RED,  # Red
        logging.CRITICAL: Fore.LIGHTRED_EX  # Dark red
    }

    def format(self, record):
        log_color = self.LEVEL_COLORS.get(record.levelno, Style.RESET_ALL)
        log_message = super().format(record)
        return log_color + log_message + Style.RESET_ALL


class LoggerManager:
    """Singleton Logger management class"""

    _instance = None
    _lock = threading.Lock()  # Thread safety

    def __new__(cls):
        with cls._lock:
            if cls._instance is None:
                cls._instance = super(LoggerManager, cls).__new__(cls)
                cls._instance._init_logger()
        return cls._instance

    def _init_logger(self):
        """Initialize Logger"""
        self.logger = logging.getLogger("logger")
        self.logger.setLevel(logging.DEBUG)

        # Create StreamHandler (output to console)
        console_handler = logging.StreamHandler()
        console_handler.setLevel(logging.DEBUG)
        formatter = ColoredFormatter("%(asctime)s - %(levelname)s - %(message)s")
        console_handler.setFormatter(formatter)

        self.logger.addHandler(console_handler)

    def change_log_path(self, log_path):
        """Change log file path"""
        for handler in self.logger.handlers[:]:
            if isinstance(handler, logging.FileHandler):
                self.logger.removeHandler(handler)
                handler.close()
        file_handler = logging.FileHandler(log_path, mode='a')
        file_handler.setLevel(logging.DEBUG)
        formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
        file_handler.setFormatter(formatter)
        self.logger.addHandler(file_handler)

    def add_file_handler(self, file_handler):
        """Add file handler"""
        file_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
        self.logger.addHandler(file_handler)

    def remove_file_handler(self, file_handler):
        """Remove file handler"""
        self.logger.removeHandler(file_handler)
        file_handler.close()

    @staticmethod
    def format_dict(data):
        """
        Check if the input variable is a dict. If so, return a formatted JSON string; otherwise, return a normal string.

        :param data: Any type of data
        :return: If data is a dict, return the string processed by json.dumps; otherwise, return the original string
        """
        if isinstance(data, dict):
            return json.dumps(data, indent=4, ensure_ascii=False)
        return str(data)


if __name__ == "__main__":
    # Get Logger instance
    logger_manager = LoggerManager()
    logger = logger_manager.logger

    # Log messages of different levels
    logger.debug("This is a DEBUG log (gray)")
    logger.info("This is an INFO log (default color)")
    logger.warning("This is a WARNING log (yellow)")
    logger.error("This is an ERROR log (red)")
    logger.critical("This is a CRITICAL log (dark red)")